/**
 * @file 按照特定接口方式封装的请求工具
 * @author zhangxueqiong
 * @date 2022/08/09
 */

// 参考https://visionmedia.github.io/superagent/docs/zh_CN/index.html
import superagent from 'superagent'; // 轻量级的渐进式ajax API
import Status from './RequestStatus';
import { message } from '@/plugin/elementplus'; // 引入el-plus消息提示
import store from '@/store';
import router from '@/router';
import i18n from '@/locale';
import { randomString } from '@/utils/tool';
// 重定向处理
export function getRedirectUrl() {
  const redirectUrl = '/';
  return redirectUrl;
}

/* eslint-disable no-throw-literal */
// 处理http请求成功的情况。此时Ajax仍有可能是业务失败的。
const defaultOnSuccess = (response: any) => {
  const { body } = response;
  if (body instanceof Blob) {
    return { data: body };
  }

  // 错误提示
  if (body.msg && body.code !== 200 && body.code !== 0) {
    message({
      type: 'error',
      message: body.msg || '',
    });
    // 未登录重定向
    if (body.code === 401) {
      store.commit('clear');
      router.replace({ path: '/login' });
    }
  }

  // 若拿到的response不是JSON，则是客户端解析出错
  if (typeof body !== 'object' || body.code === null) {
    throw {
      status: Status.CLIENT_SIDE_EXCEPTION.value,
      msg: body.msg,
    };
  }
  // 若response指明要redirect，则前端redirect
  if (body.redirect === true) {
    window.location.href = body.redirecturl || getRedirectUrl();
    throw {
      status: body.code,
      msg: body.msg,
    };
  }
  // 若状态不是成功，此时是业务失败，原样返回
  if (body.code !== Status.SUCCESS.value) {
    throw { ...body };
  }
  // 成功
  return { ...body };
};

const defaultOnFailure = (response: any) => {
  message({
    type: 'error',
    // @ts-ignore
    message: i18n.global.t('system.inter_error'),
  });
  if (response.timeout) {
    throw { status: Status.TIMEOUT.value };
  }

  throw {
    status: Status.REQUEST_ERROR.value,
    error: {
      httpStatus: response.code,
      detail: { response: response.body },
    },
  };
};

// 请求结束后的回调函数
const afterRequest = (beginTime: any) => (resp: any) => {
  // 请求结束时间
  const endTime = +new Date();
  return {
    ...resp,
    ___time___: {
      beginTime,
      endTime,
    },
  };
};

// 请求错误后的回调函数
const errorRequest = afterRequest;

/**
 * 符合特定Ajax规则的post请求方法。
 *
 * @param {string} url 请求路径
 * @param {Object} postData 发送数据
 * @param {?number} options.timeout 超时设置，默认为-1，即不设超时
 * @param {?string} options.accept 响应接收格式，默认为json
 * @param {?string} options.type 请求content-type，默认为form
 * @param {?Function} options.onSuccess 请求成功处理方法
 * @param {?Function} options.onFail 请求失败的处理方法
 * @return {Promise<Response>} 返回的promise
 */
export const postRequest = (url: any, postData: any, options: any = {}) => {
  const {
    timeout = null,
    accept = 'json',
    type = 'form',
    onSuccess = defaultOnSuccess,
    onFailure = defaultOnFailure,
    headers = {},
  } = options;
  const reqId = randomString(10);
  const beginTime = +new Date();
  let theRequest = superagent
    .post(url)
    .set(headers)
    .withCredentials()
    .accept(accept)
    .type(type)
    .send(Object.assign({ reqId }, postData));
  if (options.responseType === 'blob') {
    theRequest = superagent
      .post(url)
      .set(headers)
      .withCredentials()
      .accept(accept)
      .type(type)
      .send(postData)
      .responseType('blob');
  }
  if (timeout !== null) {
    theRequest.timeout(timeout);
  }
  return theRequest.then(onSuccess, onFailure).then(afterRequest(beginTime), errorRequest(beginTime));
};

/**
 * 符合特定Ajax规则的get请求方法。
 *
 * @param {string} url 请求路径
 * @param {string} data 请求参数
 * @param {?number} options.timeout 超时设置，默认为-1，即不设超时
 * @param {?string} options.accept 响应接收格式，默认为json
 * @param {?Function} options.onSuccess 请求成功处理方法
 * @param {?Function} options.onFail 请求失败的处理方法
 * @return {Promise<Response>} 返回的promise
 */
export const getRequest = (url: any, data: any, options: any = {}) => {
  const { timeout = null, onSuccess = defaultOnSuccess, onFailure = defaultOnFailure, headers = {} } = options;
  // 请求开始时间、结束时间、错误时间用于后续的性能监控用，暂时保留，不要删除
  // 请求开始时间
  const beginTime = +new Date();
  const reqId = randomString(10);
  const theRequest = superagent.get(url).query(Object.assign({ reqId }, data)).set(headers);
  // .withCredentials()
  // .accept(accept);
  if (timeout !== null) {
    theRequest.timeout(timeout);
  }
  return theRequest.then(onSuccess, onFailure).then(afterRequest(beginTime), errorRequest(beginTime));
};
